home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / crop.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  19KB  |  759 lines

  1. /*
  2.  * $Id: crop.c,v 0.91 1994/02/20 00:53:01 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *  Purpose:
  25.  *    Eliminate part of the image. Bounding region can be a rectangular
  26.  *    or a circular region (to be implemented).
  27.  *
  28.  *  Limitations:
  29.  *     only the viewable region is croppable.
  30.  */
  31.  
  32. #if !defined(lint) && defined(F_ID)
  33. char *id_crop = "$Id: crop.c,v 0.91 1994/02/20 00:53:01 zhao Pre-Release $";
  34. #endif
  35.  
  36. #include "bit.h"
  37. #include "extern.h"
  38.  
  39. /******************* defines and limits **********************/
  40.  
  41. #define CMAX     50        /* max border thru pop-pup */
  42. #define CROSSL   16        /* cross lenght            */
  43.  
  44. /******************* local variables ***************************/
  45.  
  46. static Rect_t imgbound, *ibr;    /* input image region              */
  47. static Rect_t regbound, *cbr;    /* current crop region             */
  48. static int bcolor = 1;        /* rubber color                    */
  49. static int cobjs;        /* region defs                     */
  50. static int ioffx, ioffy;    /* input & current image loc diff  */
  51. static int offx, offy;        /* distance from (x,y) to image    */
  52. static int croped;        /* true if image is altered        */
  53. static IPTR oim;        /* local copy of image ptr         */
  54.  
  55. /****************** local functions **************************/
  56.  
  57. static int crop_init(IPTR, int);/* initialize      */
  58. static int crop_finish(IPTR);    /* clean up        */
  59. static int crop_it(IPTR);    /* do the cropping */
  60. static int crop_popup(IPTR);    /* handle popup    */
  61. static void crop_undo(IPTR);    /* Undo last crop  */
  62. static void crop_save(IPTR);    /* change image    */
  63. static void crop_add_frame(int);/* enlarge region  */
  64. static void ras_fill(IPTR, int *);
  65.  
  66.  
  67. /********************************************************************
  68.  * Global entry point for cropping.
  69.  *
  70.  *******************************************************************/
  71.  
  72. int
  73. do_crop(IPTR im)
  74. {
  75.     int done;
  76.     short val;
  77.     long dev;
  78.  
  79.     /* initial rubber band position and size */
  80.  
  81.     if (crop_init(im, 0) < 0)
  82.     return -1;
  83.  
  84.     /* how to handle window manager's resizing, re-position etc */
  85.  
  86.     install_wm_handler(crop_init);
  87.  
  88.     /* make a local copy for undo */
  89.  
  90.     if ((oim = img_dup(im)) == 0)
  91.       {
  92.       Bark("Crop", "Can't save image");
  93.       return -1;
  94.       }
  95.  
  96.     /*
  97.      * loop until cancel or done, which is set either by ESC key or by popup
  98.      * entry
  99.      */
  100.     croped = done = 0;
  101.     do
  102.       {
  103.       dev = rubber_info(win_id, &val, &cbr->x, &cbr->y,
  104.                 &cbr->w, &cbr->h, bcolor, CROSSL);
  105.  
  106.       /*
  107.        * remember current location relative to lower left corner of the
  108.        * image. Need this info for window manager repaint events
  109.        */
  110.  
  111.       offx = cbr->x - im->xi;
  112.       offy = cbr->y - im->yi;
  113.  
  114.       ioffx = ibr->x - im->xi;
  115.       ioffy = ibr->y - im->yi;
  116.  
  117.       switch (bit_handle_event(dev, val))
  118.         {
  119.         case KEYBD:
  120.         done = (val == 27) ? -1 : 0;
  121.         break;
  122.         case ESCKEY:
  123.         done = (val > 0) ? -1 : 0;
  124.         break;
  125.         case MENUBUTTON:
  126.         done = val && crop_popup(im);
  127.         break;
  128.         default:
  129.         M_info("Crop", "Unknown event %ld %d", dev, val);
  130.         break;
  131.         }
  132.       }
  133.     while (!done);
  134.  
  135.     rubber_finish();
  136.  
  137.     if (done == -1)        /* cancel */
  138.     crop_undo(im);
  139.  
  140.     return crop_finish(im);
  141. }
  142.  
  143. /**************************************************************
  144.  * Initialize the CROP function: initial size and location
  145.  * of the rubber band. This function also handles window resizing,
  146.  * reposition events (as far as rubber band location is concerned.
  147.  *****************************************************************/
  148.  
  149. /*ARGSUSED */
  150. static int
  151. crop_init(IPTR im, int wme)
  152. {
  153.  
  154.     /* default limit is the larger of the window & image */
  155.  
  156.     set_rubber_bounds(0, Min(1, im->xi - 1), Min(1, im->yi - 1),
  157.               Max(win_w - 1, im->w + 2),
  158.               Max(win_h - 1, im->h + 2));
  159.  
  160.  
  161.     if (wme)
  162.       {
  163.       /*
  164.        * true wme indicates there is a possibility that window might be
  165.        * reszied. Figure out there the new rubber band should be where it
  166.        * has a constant relationship to image
  167.        */
  168.  
  169.       cbr->x = im->xi + offx;
  170.       cbr->y = im->yi + offy;
  171.  
  172.       /*
  173.        * must not use im->xi & im->yi as the filling bounds are against
  174.        * the OLD image bounds, not the stuff after internal filling. This
  175.        * is relevent only redraw occurs while in color selection routine
  176.        */
  177.  
  178.       ibr->x = im->xi + ioffx;
  179.       ibr->y = im->yi + ioffy;
  180.  
  181.       }
  182.     else
  183.       {
  184.       ibr = &imgbound;
  185.       cbr = ®bound;
  186.  
  187.       set_rect(ibr, im->xi, im->yi, im->w, im->h);
  188.  
  189.       /* initial size, default to viewable region */
  190.       copy_rect(cbr, union_rect(make_rect(1, 1, win_w, win_h), ibr));
  191.  
  192.       offx = offy = ioffx = ioffy = 0;
  193.  
  194.       /* make the box larger by one pixel on all sides */
  195.       shift_rect(cbr, -1, -1);
  196.       inc_rect(cbr, 2, 2);
  197.  
  198.       /*
  199.        * must turn old polygon fill on as otherwise 1pixel sized fill is
  200.        * wrong
  201.        */
  202.  
  203.       set_current_window(win_id);
  204.       glcompat(GLC_OLDPOLYGON, 1);
  205.  
  206.       }
  207.  
  208.     return 0;
  209. }
  210.  
  211. /************************************************************
  212.  * Undo all changes made so far
  213.  ************************************************************/
  214. static void
  215. crop_undo(IPTR im)
  216. {
  217.     if (croped)
  218.       {
  219.       /* can't use img_dup, ineffectual upon return */
  220.       img_dup_raster(im, oim);
  221.       im->ok = 1;
  222.  
  223.       /* once undo, text ok to be displayed again */
  224.       im->io->display = Generic_display;
  225.       im->io->display(im, 0, 1);
  226.  
  227.       crop_init(im, 0);
  228.       croped = 0;
  229.       update_image_info(im);
  230.       }
  231. }
  232.  
  233. /***************************************************************
  234.  * make all change permenent
  235.  ***************************************************************/
  236.  
  237. static void
  238. crop_save(IPTR im)
  239. {
  240.     if (croped)
  241.       {
  242.       free_image(oim);
  243.       oim = img_dup(im);
  244.  
  245.       del_text();
  246.       del_marking();
  247.  
  248.       /* re-initialize the position */
  249.       crop_init(im, 0);
  250.  
  251.       croped = 0;
  252.       }
  253. }
  254.  
  255. /*********************************************************
  256.  * make crop region n pixels larger
  257.  *******************************************************/
  258. static void
  259. interactive_frame(void)
  260. {
  261.     static int fw = 3;        /* frame width */
  262.     int xt1, yt1, tw, th, cc;
  263.  
  264.     do
  265.       {
  266.       xt1 = cbr->x - fw;
  267.       yt1 = cbr->y - fw;
  268.       tw = cbr->w + 2 * fw;
  269.       th = cbr->h + 2 * fw;
  270.       set_current_window(win_id);
  271.       rubber_moveto(&xt1, &yt1, &tw, &th);
  272.       }
  273.     while (!(cc = getint("Enter FrameWidth:", &fw, -CMAX, CMAX, 1)));
  274.  
  275.  
  276.     if (cc >= 0)        /* not cancel */
  277.       {
  278.       set_rect(cbr, xt1, yt1, tw, th);
  279.       }
  280. }
  281.  
  282.  
  283. static void
  284. crop_add_frame(int n)
  285. {
  286.  
  287.     if (n < 3)
  288.       {
  289.       shift_rect(cbr, -n, -n);
  290.       inc_rect(cbr, 2 * n, 2 * n);
  291.       }
  292.     else
  293.       {
  294.       interactive_frame();
  295.       }
  296.  
  297.     set_current_window(win_id);
  298.     rubber_moveto(&cbr->x, &cbr->y, &cbr->w, &cbr->h);
  299. }
  300.  
  301.  
  302. /************************************************************
  303.  * crop pop-up menu routines: If cancel, return -1, done 1
  304.  * else zero;
  305.  **************************************************************/
  306. static int
  307. crop_popup(IPTR im)
  308. {
  309.     static long cmenu = -1;
  310.     static char *menu =
  311.     "Crop%t|DoIt|Help|BdColor|Objs|Frame1|Frame2|FrameN|"
  312.     "Auto|Save|Undo|Cancel|Done";
  313.     int done = 0, cc;
  314.     int bot, left, top, right;
  315.  
  316.     /* if menu has not been made yet, make it now */
  317.     if (cmenu < 0)
  318.     cmenu = defpup(menu);
  319.  
  320.     switch ((cc = dopup(cmenu)))
  321.       {
  322.       case 1:            /* crop      */
  323.       done = (crop_it(im) < 0);
  324.       rubber_show(bcolor);
  325.       break;
  326.       case 2:            /* help */
  327.       help_cb((void *) 0, HELP_CROP);
  328.       break;
  329.       case 3:            /* rubber color */
  330.       ++bcolor;
  331.       bcolor %= over_pup_colors;
  332.       rubber_show(bcolor);
  333.       break;
  334.       case 4:            /* rubber object */
  335.       ++cobjs;
  336.       cobjs %= get_max_rubber_obj();
  337.       set_rubber_obj(cobjs);
  338.       rubber_show(bcolor);
  339.       break;
  340.       case 5:            /* 1 pixel larger */
  341.       case 6:            /* 2 pixel larger */
  342.       case 7:            /* n-pixel larger */
  343.       crop_add_frame(cc - 4);
  344.       break;
  345.       case 8:            /* auto              */
  346.       if (img_get_border(im, &bot, &left, &top, &right, 1))
  347.           break;
  348.  
  349.       set_rect(ibr, ibr->x + left, ibr->y + bot,
  350.            (im->w + 2) - left - right,
  351.            (im->h + 2) - top - bot);
  352.       set_current_window(win_id);
  353.       rubber_moveto(&cbr->x, &cbr->y, &cbr->w, &cbr->h);
  354.       break;
  355.       case 9:            /* save            */
  356.       crop_save(im);
  357.       break;
  358.       case 10:            /* undo */
  359.       crop_undo(im);
  360.       break;
  361.       case 11:            /* undo and return */
  362.       crop_undo(im);
  363.       done = -1;
  364.       break;
  365.       case 12:
  366.       done = 1;
  367.       break;
  368.       }
  369.     return done;
  370. }
  371.  
  372. /*******************************************************************
  373.  * Gotten the crop region icb and corresponding raster matrix m,
  374.  * insert into image structure
  375.  *******************************************************************/
  376.  
  377. static void
  378. crop_update(IPTR im, void *m, Rect_t * icb)
  379. {
  380.  
  381.     /* update the image structure */
  382.     im->w = icb->w;
  383.     im->h = icb->h;
  384.  
  385.     fill_image_struct(im, m, im->h, im->w, im->type);
  386.  
  387.     /* supress centering */
  388.     im->xi = icb->x;
  389.     im->yi = icb->y;
  390.     im->xf = icb->x + icb->w - 1;
  391.     im->yf = icb->y + icb->h - 1;
  392. }
  393.  
  394. /*******************************************************************
  395.  * Cropping by core raster manipualtions.
  396.  * If there are text or sgfs on screen, framebuffer read can not be
  397.  * avoided because lack of background rendering support (No Pixmap) in GL.
  398.  * Well, can't change that.
  399.  *
  400.  * For regions outside the image, screen will be read and may be
  401.  * refilled later.
  402.  *
  403.  ********************************************************************/
  404. static int
  405. ras_crop(IPTR im)
  406. {
  407.     void *m, *om = 0;
  408.     Rect_t cb;
  409.     const Rect_t *iu, *ir = img_rect(im);
  410.     Rect_t *icb = &cb;
  411.  
  412.     /* get the interior of the bounding region */
  413.  
  414.     copy_rect(icb, cbr);
  415.     shift_rect(icb, 1, 1);
  416.     inc_rect(icb, -2, -2);
  417.  
  418.     M_info("Crop", "Internal cropping");
  419.     show_busy(0);
  420.  
  421.  
  422.     /*
  423.      * if crop region is completely within image, the  piece of the image,
  424.      * corresponding to the crop region will be the current image. Much
  425.      * faster than the mixed regions.
  426.      */
  427.  
  428.     if (cover_rect(ir, icb))
  429.       {
  430.       m = equal_rect(ir, icb) ?
  431.           im->mraster : get_subimage(im, icb->x, icb->y, icb->w, icb->h);
  432.       crop_update(im, m, icb);
  433.       if (m != im->mraster)
  434.           free_mat(m);
  435.       end_busy();
  436.       return 0;
  437.       }
  438.  
  439.     /*
  440.      * mixed regions. Always read frame buffer first and then insert the
  441.      * raster corresponding to crop region from core directly into new image
  442.      * matrix
  443.      */
  444.  
  445.     if (!(m = get_mat(icb->h, icb->w, im->esize)))
  446.     return -1;
  447.  
  448.     Rectread(icb->x, icb->y,
  449.          icb->x + icb->w - 1, icb->y + icb->h - 1, ((char **) m)[0]);
  450.  
  451.     /* get the union of the two regions */
  452.     if ((iu = union_rect(ir = img_rect(im), icb)))
  453.       {
  454.       om = equal_rect(ir, iu) ?
  455.           im->mraster : get_subimage(im, iu->x, iu->y, iu->w, iu->h);
  456.       put_submat(m, icb->h, icb->w, om, iu->y - icb->y,
  457.              iu->x - icb->x, iu->h, iu->w, im->esize);
  458.       }
  459.     else
  460.       {
  461.       M_warn("Crop", "No union found");
  462.  
  463.       }
  464.  
  465.     if (om && om != im->mraster)
  466.     free_mat(om);
  467.  
  468.     crop_update(im, m, icb);
  469.     end_busy();
  470.  
  471.     return 0;
  472. }
  473.  
  474. /*********************************************************************
  475.  * Cropping via framebuffer read. Could look bad if on Indigoes
  476.  * or machines with less than 24 bits framebuffer
  477.  ********************************************************************/
  478.  
  479. static int
  480. fb_crop(IPTR im)
  481. {
  482.     /* the bounding rect is 1 pixel larger than both sides */
  483.     return read_screen(im, cbr->x + 1, cbr->y + 1, cbr->w - 2, cbr->h - 2);
  484. }
  485.  
  486. /*******************************************************************
  487.  * When the cropping region is larger than current image, have a choice
  488.  * to fill the empty regions. This function does the interactive
  489.  * part of the filling. The actually filling is done by memory copy
  490.  * in crop_it
  491.  *******************************************************************/
  492.  
  493. /* default fill color */
  494. static int lc[4] =
  495. {
  496.     0, 0, 0, 0
  497. };
  498.  
  499. /***************************************************************
  500.  * Fill the region that is not the union of (x,y, bw, bh)
  501.  * and (xi, yi, xf, yf)
  502.  **************************************************************/
  503. static void
  504. screen_fill_only(void)
  505. {
  506.     int fx2 = cbr->x + cbr->w - 1;
  507.     int fy2 = cbr->y + cbr->h - 1;
  508.     int xf = ibr->x + ibr->w - 1;
  509.     int yf = ibr->y + ibr->h - 1;
  510.  
  511.     if (union_rect(ibr, cbr) == 0)
  512.       {
  513.       rectfi(cbr->x, cbr->y, cbr->x + cbr->w - 1, cbr->y + cbr->h - 1);
  514.       return;
  515.       }
  516.  
  517.     if (cbr->x < ibr->x - 1)
  518.       {
  519.       rectfi(cbr->x + 1, cbr->y + 1, ibr->x - 1, fy2 - 1);
  520.       }
  521.  
  522.     if (cbr->y < ibr->y - 1)
  523.       {
  524.       rectfi(cbr->x + 1, cbr->y + 1, fx2 - 1, ibr->y - 1);
  525.       }
  526.  
  527.     if (fx2 > xf + 1)
  528.       {
  529.       rectfi(xf + 1, cbr->y + 1, fx2 - 1, fy2 - 1);
  530.       }
  531.  
  532.     if (fy2 > yf + 1)
  533.       {
  534.       rectfi(cbr->x + 1, yf + 1, fx2 - 1, fy2 - 1);
  535.       }
  536. }
  537.  
  538. /**********************************************************************
  539.  * Fill and show it
  540.  *********************************************************************/
  541. static void
  542. screen_fill(int c[])
  543. {
  544.     set_current_window(win_id);
  545.     reshapeviewport();
  546.  
  547.     Color((RGB2CPACK(c[0], c[1], c[2])), c[3]);
  548.     screen_fill_only();
  549.  
  550.     if (double_buf)
  551.       {
  552.       swapbuffers();
  553.       screen_fill_only();
  554.       }
  555. }
  556.  
  557.  
  558. /*********************************************************************
  559.  * Similar to screen_fill, but fill the raster instead as well
  560.  ********************************************************************/
  561. static void
  562. ras_fill(IPTR im, int *c)
  563. {
  564.     void *m = im->mraster;
  565.     size_t e = im->esize;
  566.     rgba_t fc;
  567.     int delta;
  568.     int x2 = cbr->x + cbr->w - 1;
  569.     int y2 = cbr->y + cbr->h - 1;
  570.     int iw = im->w, ih = im->h;
  571.     int xf = ibr->x + ibr->w - 1;
  572.     int yf = ibr->y + ibr->h - 1;
  573.  
  574.  
  575.     if (c == 0)
  576.     c = lc;
  577.  
  578.     fc = (IS_CI(im)) ? c[3] : (rgba_t) Pack(c[0], c[1], c[2]);
  579.  
  580. #if 1
  581.     /* completely disjoint */
  582.     if (union_rect(ibr, img_rect(im)) == 0)
  583.       {
  584.       init_mat(im->mraster, im->h, im->w, im->esize, fc);
  585.       screen_fill(c);
  586.       return;
  587.       }
  588. #endif
  589.     /* fill_submat uses ( r = r1; r<=r2; r++) */
  590.     if ((delta = Min(ibr->x, x2 - 1) - cbr->x - 1) > 0)
  591.       {
  592.       fill_submat(m, 0, ih - 1, 0, delta - 1, fc, e);
  593.       }
  594.  
  595.     if ((delta = Min(ibr->y, yf - 1) - cbr->y - 1) > 0)
  596.       {
  597.       fill_submat(m, 0, delta - 1, 0, iw - 1, fc, e);
  598.       }
  599.  
  600.     if ((delta = x2 - 1 - Max(xf, cbr->x + 1)) > 0)
  601.       {
  602.       fill_submat(m, 0, ih - 1, iw - delta, iw - 1, fc, e);
  603.       }
  604.  
  605.     if ((delta = y2 - 1 - Max(yf, cbr->y + 1)) > 0)
  606.       {
  607.       fill_submat(m, ih - delta, ih - 1, 0, iw - 1, fc, e);
  608.       }
  609.  
  610.     /* also show on screen */
  611.     screen_fill(c);
  612. }
  613.  
  614. /******************************************************************
  615.  * actually doing the crop by calling other routine if necessary
  616.  ********************************************************************/
  617. static int
  618. crop_it(IPTR im)
  619. {
  620.     short val;
  621.     int internal, fill;
  622.     Rect_t trect;
  623.  
  624. #ifdef MTRACE
  625.     M_trace("CropIt", "Entering");
  626. #endif
  627.  
  628.     rubber_hide();
  629.  
  630.     /* true region is 1pixel larger on all sides */
  631.     copy_rect(&trect, cbr);
  632.     shift_rect(&trect, 1, 1);
  633.     inc_rect(&trect, -2, -2);
  634.  
  635.     set_current_window(win_id);
  636.  
  637.     frontbuffer(1);
  638.     clear_outside_rect(&trect);
  639.  
  640.     /* disable text  & sgf displaying */
  641.     im->io->display = display_image;
  642.  
  643.     /* replace raster if no text and sgfs */
  644.  
  645.     internal = (!always_readscrn && !number_of_text() && !number_of_sgf());
  646.     set_current_window(win_id);
  647.     reshapeviewport();
  648.  
  649.     if ((internal ? ras_crop : fb_crop) (im) < 0)
  650.     return -1;
  651.  
  652.     update_image_info(im);
  653.  
  654.     /* fill if neccessary. crop_fill == 0 turns off fill */
  655.  
  656.     fill = (!cover_rect(ibr, &trect) && (crop_fill == 2 ||
  657.         (crop_fill == 1 && yes_no("FillCropRegion", "", "Fill ?", 0))));
  658.  
  659.     /* do redraw and eat other events */
  660.  
  661.     (void) bit_qread(&val);
  662.  
  663.     /*
  664.      * remember where the bounds and old image locatations relative to
  665.      * cropped image. Useful if redraw occurs to re-display rubber band
  666.      */
  667.  
  668.     ioffx = ibr->x - im->xi;
  669.     ioffy = ibr->y - im->yi;
  670.  
  671.     offx = cbr->x - im->xi;
  672.     offy = cbr->y - im->yi;
  673.  
  674.     if (fill)
  675.       {
  676.  
  677.       /* show default color */
  678.       ras_fill(im, lc);
  679.  
  680.       /* what to do if color changes */
  681.       set_getcolor_cb(screen_fill);
  682.  
  683.       /*
  684.        * never returns unless form is finished. For every color change,
  685.        * screen_fill will be called
  686.        */
  687.  
  688.       get_color(im, lc, 1);    /* block */
  689.  
  690.       /*
  691.        * could stick the following into screen_fill, but it could be
  692.        * slow. This way although if unknown repaints occurs, the screen
  693.        * could be messed up, but the image is not damaged and we have a
  694.        * much better response
  695.        */
  696.  
  697.       /*
  698.        * do final actually filling. It is always a good thing to fill
  699.        * internally
  700.        */
  701.       ras_fill(im, lc);
  702.       }
  703.     croped = 1;
  704.     frontbuffer(!double_buf);
  705.  
  706. #ifdef MTRACE
  707.     M_trace("CropIt", "Returning");
  708. #endif
  709.     return 0;
  710. }
  711.  
  712. /**********************************************************************
  713.  *          clean up
  714.  **********************************************************************/
  715. static int
  716. crop_finish(IPTR im)
  717. {
  718.  
  719.     if (im->ok > 0)
  720.       {
  721.       free_image(oim);
  722.       }
  723.     else
  724.       {
  725.       Bark("Crop", "Something is not right");
  726.       free_image_mem(im);
  727.       memcpy(im, oim, sizeof(*oim));
  728.       croped = 0;
  729.       }
  730.  
  731.     im->ok = 1;
  732.     if (croped)
  733.       {
  734.       if (!keepmisc)
  735.         {
  736.         del_text();
  737.         del_marking();
  738.         }
  739.       im->io->display(im, -1, 1);
  740.       }
  741.  
  742.     /*
  743.      * since there is no mask set, if framebuffer is read, we got full
  744.      * 12bits, need to mask off the un-used one otherwise colormap overflown.
  745.      */
  746.  
  747.     if (IS_CI(im))
  748.     do_ci_mask(im->raster, im->w * im->h, im->cmap->colors - 1);
  749.  
  750.     remove_wm_handler(crop_init);
  751.  
  752.     im->io->display = Generic_display;
  753.  
  754.     if (double_buf)
  755.     im->io->display(im, 0, 1);
  756.  
  757.     return 0;
  758. }
  759.